Mur d'eau
Nous proposons, en collaboration avec la filière STI2D pour la partie technique, de travailler sur la réalisation d'un mur d'eau numérique. Il s'agit d'un ensemble de vannes commandées informatiquement afin d'afficher des formes, des images voir des messages à l'aide de filets d'eaux. Voici quelques exemples existants en vidéo :

Il existe également des versions en 3 dimensions de ce dispositif.
Au travers d'exercices à la difficulté croissante, programmer des animations pour un mur d'eau numérique "simulé" (voir ci-dessous). Les réalisations pourront éventuellement rejoindre les projets des élèves de STI2D et commander les vannes d'un mur d'eau bien réel.
Le mur d'eau simulé ci-dessous est paramétrable (dimensions, vitesse, vannes) et programmable en JavaScript. Une version sans énoncé, plus pratique , est également accessible ici.
Il est possible de changer certains paramètres du mur dans les champs de saisie. La validation se fait avec Entrée.
Paramètre Unité Valeurs valides
Largeur pixel de 300px à 1000px
Longueur pixel de 300px à 1000px
Nombre de vannes - de 1 à 20
Vitesse verticale pixel par seconde de 0px/s à 1000px/s
Il est possible de contrôler "manuellement" les vannes en cliquant simplement sur le tuyau que l'on souhaite ouvrir ou fermer. Le témoin lumineux indique l'état de la vanne. La zone de texte grise permet de commander les vannes à l'aide de deux fonctions simples open() et close(). Il faut préciser l'indice de la vanne que l'on souhaite commander, le temps de départ de l'action(en millisecondes) et éventuellement sa durée.
Commande Arguments Exemple
open(indiceVanne,t_depart,duree)
  • int indiceVanne : indice de la vanne compris entre 0 et N_vanne-1.
  • float t_depart : instant d'ouverture de la vanne s'ouvre (en ms).
  • float duree : durée (en ms) avant la fermuture de la vanne.
open(0, 1000, 2000) : ouvre la première vanne au bout de une seconde pendant deux secondes.
open(indiceVanne,t_depart)
  • int indiceVanne : indice de la vanne.
  • float t_depart : instant d'ouverture de la vanne (en ms).
open(0, 200) : ouvre la première vanne au bout de 200ms et la laisse ouverte.
close(indiceVanne,t_depart)
  • int indiceVanne : indice de la vanne.
  • float t_depart : instant de fermeture de la vanne(en ms).
close(1, 1000) : ferme la deuxième vanne après 1s du départ.
  • L'instant initial t=0 démarre au moment où l'utilisateur clique sur .
  • L'ordre dans lequel on écrit les commandes n'a pas d'importance sur l'ordre d'ouverture des vannes. Ce sont les valeurs données pour t_depart
  • Le code donné n'est pas exécuté au fur et à mesure que l'eau tombe. Il permet d'enregistrer l'"agenda" des vannes. Lorsque qu'il est validé, les vannes sont lancées sans qu'on ne puisse plus intervenir.
Commencer par ouvrir le mur d'eau simulé dans un nouvel onglet. Ca sera plus pratique pour suivre les consignes sans remonter tout en haut de page pour chaque test. Pour commencer utilisons les commandes manuelles : Faire varier les dimensions du mur d'eau (valider avec Entrée) Commander les vannes à l'aide de la souris Faire varier la vitesse d'écoulement Combien de temps met un filet d'eau pour s'écouler le long d'un mur long de 400px à une vitesse de 250px/s ? Dans la suite de l'exercice, nous garderons les valeurs par défaut.

Indice 1

Indice 2

Indice 3

Indice 4

On se souvient de la formule $v=\frac{d}{t}$, mais aussi de sa variante $t=...$
A partir de maintenant, nous programmerons le comportement du mur avec les fonctions décrites avant : En utilisant la commande open() (et éventuellement close()) : Ouvrir les 6 vannes immédiatement et pendant 1s. Ouvrir une vanne sur deux sans les refermer. Combiner les deux commandes précédentes pour produire l'effet suivant : Ajouter 3 commandes pour fermer les vannes restées ouverte à la fin de l'animation.

Indice 1

Pour la première vanne (i=0), commencer à t=0, pendant 1000ms : open(0,0,1000) puis écrire l'instruction pour les 5 autres vannes. Lancer avec .

Indice 2

Ouvrir la première vanne sans la refermer s'écrit open(0,0) , puis compter de 2 en 2...

Indice 3

Appliquer la question 1 aux vannes 1, 3 et 4. Appliquer la question 2 pour les autres...

Indice 4

Fermer la 1ère vanne au bout de 4s (4000ms) s'écrit close(0,4000)
Il est très fortement conseillé d'utiliser un papier un crayon pour schématiser les filets d'eau et réfléchir aux temps d'ouverture des vannes. Réaliser un motif en escaliers :

Indice 1

Pour créer un décalage entre un filet et celui d'après, quand on ferme la vanne i, on doit ouvrir la vanne i+1

Indice 2

On ouvre chaque vanne pendant la même durée (par exemple 200ms).

Indice 3

Pour les deux premières vannes, on peut exécuter : open(0,0,200) open(1,200,200)

Indice 4

Quand on arrive à la vanne i=5, on revient en arrière avec i=4, 3, 2,...
En plus des fonctions open() et close(), la zone de commande est capable de reconnaître et interpréter du JavaScript. Ca va être utile pour déclarer et utiliser des variables. Pour déclarer une variable ma_variable et lui affecter une valeur valou le résultat d'un calcul : var ma_variable = val Lorsqu'une variable a été déclarée, il n'est pas nécessaire d'utiliser la commande var. On souhaite créer un rectangle d'eau de hauteur h que l'on fera varier comme on le souhaite. Commencer par déclarer les variables v=250 et h=30. Utiliser une formule sur h et v pour affecter à une variable dt le temps d'ouverture nécessaire pour créer un filet d'eau de hauteur h. Utiliser la formule précédente pour afficher des pointillés verticaux deux fois plus longs que l'espace entre eux : Faire varier la valeur de h pour étirer ou raccourcir la figure obtenue.

Indice 1

Le temps $t$ nécessaire pour parcourir $d$ à la vitesse $v$ est calculé par la formule $t=\frac{d}{v}$. Attention aux unités !!!!

Indice 2

Il faut déclarer et donner une valeur à la variable dt au début du programme. Ensuite on l'utilise dans les arguments de open().

Indice 2'

La durée d'ouverture doit être deux fois plus longue que le temps de fermeture donc : open(0,...,2*dt)

Indice 3

Tester différentes valeurs pour h
  • Il est vivement conseillé de créer des variables pertinentes pour adapter le code au rendu souhaité sans avoir à effectuer trop de modifications. Ca sera très utile pour porter le code sur un mur d'eau réel.
  • Les commentaires d'une ligne sont préfixés par //. Les commentaires sur plusieurs lignes sont placés entre /* ...... */. Commenter le code est une bonne pratique en programmation, ça permet au lecteur de s'y retrouver plus rapidement.
L'utilisation de boucles for nous permettra d'effectuer en quelques lignes l'ouverture de plusieurs vannes. Sur un petit mur d'eau le gain n'est pas forcément énorme, mais souvenez vous du mur présenté par la vidéo d'introduction... Pour utiliser une boucle itérant une variable i de 0 à N-1 on peut s'y prendre de la manière suivante : for(var i=0 ; i<N ; i++){ //instructions répétées utilisant la variable i } Utilisez une boucle for itérant un indice i de 0 à 5 afin d'ouvrir toutes les vannes. De manière similaire, utilisez une boucle pour ouvrir durant 100ms les vannes 0, 2 et 4. Même question pour les vannes 1, 3 et 5. Adaptez ces deux questions pour afficher des rectangles décalés : les vannes impaires doivent se déclencher 100ms plus tard que les vannes paires. En réutilisant la question précédente, répétez 10 fois les deux boucles afin de produire le damier suivant : On pourra utiliser pour ça une boucle itérant une variable $k$ allant de 0 à 9. Cette variable pourra être utilisée pour déterminer à quel moment chaque vanne s'ouvre.

Indice 1

La boucle doit itérer i le numéro de la vanne de 0 à 5. La fonction open() n'apparait qu'une fois dans la boucle.

Indice 2a

0, 2 et 4 sont pairs, et correspondent donc à un indice 2*i pour i valant 0, 1 et 2.

Indice 2b

1, 3 et 5 sont impairs, et correspondent donc à un indice 2*i+1 pour i valant 0, 1 et 2.

Indice 2c

Deux boucles doivent se suivre : la première concerne les vannes paires (voir question 2a). La deuxième concerne les vannes impaires (voir question 2b).

Indice 3

Répéter le code de la question 2c 10 fois : on peut l'enfermer dans une boucle itérant sur k de 0 à 9. La variable doit être différente de i (indice des vannes).

Indice 3'

Attention au temps de départ pour la k-ième répétition. dt est le temps d'ouverture. A chaque étape il s'est écoulé un temps 2*dt,...
Les fonctions sont utiles pour résumer en une seule commande un ensemble complexe de commandes que l'on souhaite rappeler souvent. Pour déclarer une fonction nom_fonction prenant les arguments arg1, arg2, ... et renvoyant une valeur (ce n'est pas obligatoire) valeur_retour, on la déclare de la manière suivante : nom_fonction=function(arg1, arg2, ...){ /*instructions ..... ..... */ return valeur_retour } Les fonctions que l'on déclare ici ne renvoient pas de valeur, l'instruction return n'est donc pas nécessaire. Une fois la fonction créée, il faut l'appeler pour qu'elle s'exécute : //exécuter une première fois la fonction : var valeur1 = nom_fonction(1,x) //exécuter une deuxième fois la fonction sans stocker sa valeur de retour : nom_fonction(2,x+1) Créer une fonction openAll(t_depart, duree) qui prend en argument t_depart une entier représentant l'instant d'ouverture des vannes en ms, duree la durée d'ouverture en ms. Cette fonction devra ouvrir en même temps toutes les vannes du mur pour tracer un bandeau horizontal. Appeler 10 fois cette fonction dans une boucle afin d'afficher le motif suivant :

Indice 1

Créer la fonction openAll=function(t_depart,duree). Elle ne renvoie pas de valeur.

Indice 1'

Il faut utiliser une boucle itérant i pour ouvrir toutes les vannes de 0 à 5.

Indice 2

La fonction openAll() doit apparaître une seule fois dans une boucle. Cette fois, l'indice peut être i car il n'apparaît plus directement.

Programmer une fonction permettant le rendu visuel de petites images représentées sous la forme de tableaux de nombres ($1$ représente la présence d'eau, et $0$ l'absence d'eau).

Appliquer la fonction de manière à afficher des lettres de l'alphabet, puis des messages textuels.

Vous pourrez utiliser les tableaux de nombres suivant pour tester votre code : //nécessite 7 vannes smiley=[ [0,0,1,1,1,0,0], [0,1,0,0,0,1,0], [1,0,1,0,1,0,1], [1,0,0,0,0,0,1], [1,1,0,0,0,1,1], [1,0,1,1,1,0,1], [0,1,0,0,0,1,0], [0,0,1,1,1,0,0] ] //nécessite 11 vannes : invader=[ [0,0,1,0,0,0,0,0,1,0,0], [0,0,0,1,0,0,0,1,0,0,0], [0,0,1,1,1,1,1,1,1,0,0], [0,1,1,0,1,1,1,0,1,1,0], [1,1,1,1,1,1,1,1,1,1,1], [1,0,1,1,1,1,1,1,1,0,1], [1,0,1,0,0,0,0,0,1,0,1], [0,0,0,1,1,0,1,1,0,0,0], ] Le programme devra inclure les solutions suivantes :
  • La hauteur h des rectangles de base formant l'image devra être calculée en fonction de la vitesse de chute de l'eau et de la hauteur du mur.
  • Deux boucles imbriquées parcourant chaque ligne (d'indice i) du tableau et chaque valeur (d'indice j) de chaque ligne devront être utilisée.
  • Le programme permettant d'afficher ces tableaux devra être réalisé sous la forme d'une fonction afficheTableau(T) qui prend en argument un tableau de nombres représentant une image.
  • Créer des tableaux représentant graphiquement quelques lettres à utiliser pour un message textuel.
  • Programmer une fonction afficheLettre(char) permettant d'afficher une lettre à l'aide des tableaux créés.
  • Programmer une fonction afficheTexte(txt) permettant d'afficher un message textuel défilant verticalement une lettre après l'autre.
  • Conserver les animations réalisées dans un ou plusieurs fichiers texte que l'on sauvegardera régulièrement. Penser à y ajouter des commentaires pour décrire le code.
  • Pour aller plus loin, il est possible d'adapter des créations d'ascii art existantes (voir ce site par exemple.)
  • Ce mur virtuel est une petite simulation, il est préférable de ne pas essayer d'afficher des motifs excessivement longs (moins de 1000 instructions) et aussi d'éviter les while sous peine de faire crasher le navigateur...
  • Attention, les premières "gouttes" qui coulent correspondent au bas de l'image. Il faut commencer par afficher le bas du tableau.
  • On utilisera la variable i comme indice des lignes, et j comme indice des colonnes.
Il sera nécessaire d'accéder aux éléments de la liste et de connaître leur longueur.
Commande Commentaire
L[i] renvoie le ième élément de la liste L
L[i][j] renvoie l'élément de la ième ligne et de la jème colonne
L.length L'attribut length contient la longueur de la liste L
Les chaînes de caractère fonctionne selon la même syntaxe.